function findTargetSumWays(nums: number[], target: number): number {

//? 把数组分成两个组合left, right。left + right = sum, left - right = target  =>  left = (sum + target)/2
    const sum: number = nums.reduce((a: number, b: number): number => a + b);
    if ((sum + target) % 2 || Math.abs(target) > sum) return 0;  // 无解的情况
    const left: number = (sum + target) / 2;

//? 也就是说要达到条件，left（总和）需要为(sum + target) / 2。故就将问题转化为装满容量为left的背包有多少种方法
    /*
     ? dp[i]表示装满容量为i的背包有多少种方法

     ? 递归公式 dp[j] += dp[j - nums[i]]

     ? 解释：当前值为num[i] => 剩下总容量为left - num[i] 此时dp[left - num[i]]就是装满当前剩余容量的背包有的方法数
     ? 那么递推公式为什么是这些的累加呢？
     ? dp[j] = dp[j]+dp[j-nums[i]]，表示能凑出和为 j 的方案数应该为：不选 nums[i] 的方案数 dp[j] 加上选择 nums[i] 的方案数 dp[j-nums[i]]。
     */
    const dp: number[] = new Array(left + 1).fill(0);
    dp[0] = 1;  //? 装满容量为0的背包有1种方法（什么也不装）
    for (let i: number = 0; i < nums.length; i++) {
        for (let j: number = left; j >= nums[i]; j--) {
            //? 大家也可以记住，在求装满背包有几种方法的情况下，递推公式一般为：
            dp[j] += dp[j - nums[i]];
        }
    }
    return dp[left];
}
